通过 CSS 逻辑属性 Level 2 探索 Web 布局的未来。这份综合指南涵盖了新属性、实践范例以及如何构建真正全球化的、支持各种书写模式的网站。
CSS 逻辑属性 Level 2:通过增强的书写模式支持构建真正的全球化 Web
几十年来,Web 开发人员一直使用源于物理世界的词汇来构建布局:top、bottom、left 和 right。我们设置 margin-left、padding-top 和 border-right。当 Web 主要是一种从左到右、从上到下的媒介时,这种心智模型很好地服务了我们。然而,Web 是全球性的。它是一个面向所有语言和文化的平台,其中许多语言和文化并不遵循这种简单的方向流。
像阿拉伯语和希伯来语这样的语言是从右到左书写的。传统的日语和中文可以垂直书写,从上到下、从右到左。将物理的、从左到右的 CSS 模型强加于这些书写系统,会导致布局混乱、用户体验糟糕以及大量的代码覆盖。这就是 CSS 逻辑属性和值的用武之地,它代表了从物理方向到流相对(flow-relative)、逻辑方向的根本性范式转变。虽然 Level 1 奠定了基础,但 CSS 逻辑属性 Level 2 则完善了整个体系,为我们提供了构建真正通用的、具有书写模式感知能力的用户界面所需的工具。
这份综合指南将带您深入了解 Level 2 带来的增强功能。我们将从回顾核心概念开始,然后探索填补空白的新属性和值,最后,通过构建一个能够无缝适应任何书写模式的组件,将所有知识付诸实践。准备好彻底改变您对 CSS 布局的看法吧。
快速回顾:逻辑属性的核心概念 (Level 1)
在我们领会 Level 2 的新增内容之前,我们必须对 Level 1 奠定的基础有扎实的理解。整个系统建立在两个关键概念之上:书写模式(writing mode)以及由此产生的块轴(block axis)和行内轴(inline axis)。
四种书写模式
writing-mode CSS 属性决定了文本的布局方向。虽然我们常常认为默认值是理所当然的,但有几个值可以从根本上改变内容在页面上的流动方式:
- horizontal-tb: 这是大多数西方语言的默认设置。文本水平流动(行内轴)从左到右(或根据 direction 从右到左),行从上到下(块轴)堆叠。
- vertical-rl: 用于传统的东亚排版(例如,日语、中文)。文本垂直流动,从上到下(行内轴),行从右到左(块轴)堆叠。
- vertical-lr: 与上述类似,但行从左到右(块轴)堆叠。不太常见,但在某些场景(如蒙古文)中使用。
- sidelong-rl / sidelong-lr: 这些用于特定用例,当您希望将字形侧向放置时。在常规 Web 内容中不太常见。
关键概念:块轴 vs. 行内轴
这是需要掌握的最重要的概念。在一个逻辑的世界里,我们不再考虑“垂直”和“水平”,而是开始用块(block)和行内(inline)轴来思考。它们的方向完全取决于 writing-mode。
- 行内轴(Inline Axis)是单行内文本流动的方向。
- 块轴(Block Axis)是新行堆叠的方向。
让我们看看这是如何运作的:
- 在标准英语中 (writing-mode: horizontal-tb):行内轴是水平的,块轴是垂直的。
- 在传统日语中 (writing-mode: vertical-rl):行内轴是垂直的,块轴是水平的。
由于这些轴可以切换,像 width 和 height 这样的属性就变得模棱两可。width 是沿水平轴的尺寸还是沿行内轴的尺寸?逻辑属性解决了这种模糊性。我们现在为每个轴都定义了 start 和 end:
- block-start: 在英语中是“顶部”,但在垂直日语中是“右侧”。
- block-end: 在英语中是“底部”,但在垂直日语中是“左侧”。
- inline-start: 在英语中是“左侧”,但在垂直日语中是“顶部”。
- inline-end: 在英语中是“右侧”,但在垂直日语中是“底部”。
物理属性到逻辑属性的映射 (Level 1)
Level 1 引入了一套全面的从物理属性到逻辑属性的映射。以下是一些关键示例:
- width → inline-size
- height → block-size
- min-width → min-inline-size
- max-height → max-block-size
- margin-left → margin-inline-start
- margin-right → margin-inline-end
- margin-top → margin-block-start
- margin-bottom → margin-block-end
- padding-left → padding-inline-start
- padding-top → padding-block-start
- border-right → border-inline-end
- border-bottom → border-block-end
- left / right (用于定位) → inset-inline-start / inset-inline-end
- top / bottom (用于定位) → inset-block-start / inset-block-end
Level 1 还为我们提供了有用的简写属性,如 margin-inline (用于 start 和 end) 和 padding-block (用于 start 和 end)。
欢迎来到 Level 2:新特性及其重要性
虽然 Level 1 是一个巨大的进步,但它留下了一些明显的空白。某些基础的 CSS 属性,如 float、clear 和 resize,没有逻辑上的等价物。此外,像 border-radius 这样的属性无法进行逻辑控制,迫使开发人员在进行精细样式设计时退回到物理属性。这意味着你可以用逻辑属性构建 90% 的布局,但仍然需要为不同的书写模式编写物理属性的覆盖代码,这在一定程度上违背了初衷。
CSS 逻辑属性 Level 2 直接解决了这些不足。它不是引入一个全新的激进系统,而是为了完善 Level 1 开始的体系。它主要通过两种方式实现这一目标:
- 为本质上是物理的旧 CSS 功能引入新的逻辑属性和值 (例如 float)。
- 为之前被忽略的复杂简写属性添加逻辑属性映射 (例如 border-radius)。
有了 Level 2,一个完全流相对的样式系统的愿景几近完成,使我们能够构建复杂、美观且健壮的组件,这些组件可以在任何地方为任何人工作,而无需任何 hack 或覆盖。
深入探讨:Level 2 中的新逻辑值和属性
让我们来探索 Level 2 为我们的开发工具箱带来的最具影响力的补充。这些工具填补了空白,赋能了真正通用的组件设计。
Float 与 Clear:逻辑革命
多年来,float 属性一直是 CSS 布局的基石,但其值 left 和 right 是物理方向的定义。如果你在英文段落中将图片浮动到左侧,它看起来是正确的。但如果将文档方向切换为从右到左(RTL)以适应阿拉伯语,图片现在就在文本块的“错误”一侧。它应该在右侧,也就是行的开始处。
Level 2 为 float 属性引入了两个新的逻辑关键字:
- float: inline-start; 这会使元素浮动到行内方向的起始位置。在 LTR 语言中,这是左侧。在 RTL 语言中,这是右侧。在 vertical-rl 书写模式中,这是顶部。
- float: inline-end; 这会使元素浮动到行内方向的结束位置。在 LTR 中,这是右侧。在 RTL 中,这是左侧。在 vertical-rl 中,这是底部。
同样,用于控制内容围绕浮动元素换行的 clear 属性也获得了其逻辑对应项:
- clear: inline-start; 清除 inline-start 侧的浮动。
- clear: inline-end; 清除 inline-end 侧的浮动。
这是一个颠覆性的改变。您现在可以创建经典的图文环绕布局,它能自动适应任何语言方向,而无需一行额外的 CSS。
通过逻辑 Resize 实现增强控制
resize 属性通常用于 textarea,允许用户调整元素大小。其传统值为 horizontal、vertical 和 both。但在垂直书写模式中,“horizontal”意味着什么?它仍然意味着沿物理水平轴调整大小,这可能不是用户或设计师的意图。用户可能希望沿其行内轴调整元素大小,以使行更长或更短。
Level 2 为 resize 引入了逻辑值:
- resize: inline; 允许沿行内轴调整大小。
- resize: block; 允许沿块轴调整大小。
在英文的 textarea 上使用 resize: block; 允许用户使其更高。在垂直书写模式中使用它,则允许用户使其更宽(这是块方向)。它就是这么好用。
`caption-side`:表格标题的逻辑定位
caption-side 属性决定了表格 caption 的位置。旧值为 top 和 bottom。同样,这些是物理的。如果设计师的意图是将标题放在表格内容“之前”,top 对于水平书写模式是有效的。但在 vertical-rl 模式中,块流的“开始”是在右侧,而不是顶部。
Level 2 提供了逻辑解决方案:
- caption-side: block-start; 将标题放置在块流的开始处。
- caption-side: block-end; 将标题放置在块流的结束处。
`text-align`:一个基础逻辑值
虽然 text-align 的值 start 和 end 已经存在了一段时间,但它们是逻辑属性哲学的核心部分,值得再次强调。使用 text-align: left; 是一个常见的错误,它会立即在 RTL 语言中引起布局问题。正确的现代方法是始终使用:
- text-align: start; 将文本对齐到行内方向的开始处。
- text-align: end; 将文本对齐到行内方向的结束处。
Level 2 的皇冠之珠:逻辑 `border-radius`
也许 Level 2 中最重要和最强大的新增功能是用于逻辑控制边框圆角的一系列属性。以前,如果你想让一张卡片只在“顶部”有圆角,你会使用 border-top-left-radius 和 border-top-right-radius。这在垂直书写模式中完全失效,因为“顶部”的角现在是 start-start 和 end-start 角。
Level 2 引入了四个新的详细属性,它们以流相对的方式映射到元素的四个角。命名约定是 border-[block-edge]-[inline-edge]-radius。
- border-start-start-radius: 块轴开始边与行内轴开始边相交的角。
- border-start-end-radius: 块轴开始边与行内轴结束边相交的角。
- border-end-start-radius: 块轴结束边与行内轴开始边相交的角。
- border-end-end-radius: 块轴结束边与行内轴结束边相交的角。
起初这可能很难想象,所以让我们为不同的书写模式进行映射:
在 `writing-mode: horizontal-tb` (例如,英语) 中的 `border-radius` 映射
- border-start-start-radius 映射为 top-left-radius。
- border-start-end-radius 映射为 top-right-radius。
- border-end-start-radius 映射为 bottom-left-radius。
- border-end-end-radius 映射为 bottom-right-radius。
在 `writing-mode: horizontal-tb` 且 `dir="rtl"` (例如,阿拉伯语) 中的 `border-radius` 映射
在这里,行内方向是翻转的。
- border-start-start-radius 映射为 top-right-radius。(块轴开始是 top,行内轴开始是 right)。
- border-start-end-radius 映射为 top-left-radius。
- border-end-start-radius 映射为 bottom-right-radius。
- border-end-end-radius 映射为 bottom-left-radius。
在 `writing-mode: vertical-rl` (例如,日语) 中的 `border-radius` 映射
在这里,两个轴都旋转了。
- border-start-start-radius 映射为 top-right-radius。(块轴开始是 right,行内轴开始是 top)。
- border-start-end-radius 映射为 bottom-right-radius。
- border-end-start-radius 映射为 top-left-radius。
- border-end-end-radius 映射为 bottom-left-radius。
通过使用这些新属性,您可以定义与内容流语义相关的圆角,而不是与物理屏幕相关。无论语言或文本方向如何,“start-start”角将永远是正确的角。
实践:构建一个全球化就绪的组件
理论很棒,但让我们看看这在实践中是如何工作的。我们将构建一个简单的个人资料卡片组件,首先使用旧的物理属性,然后将其重构为使用来自 Level 1 和 Level 2 的现代逻辑属性。
该卡片将有一个浮动到一侧的图片、一个标题、一些文本,以及一个装饰性边框和圆角。
“旧”方法:脆弱的、基于物理属性的卡片
这是几年前我们可能设计这张卡片的方式:
/* --- CSS (物理属性) --- */
.physical-card {
width: 300px;
padding: 20px;
margin-bottom: 20px;
border: 1px solid #ccc;
border-left: 5px solid steelblue;
border-top-left-radius: 8px;
border-bottom-left-radius: 8px;
}
.physical-card .avatar {
float: left;
width: 80px;
height: 80px;
margin-right: 15px;
}
.physical-card h3 {
margin-top: 0;
text-align: left;
}
在标准的英语 LTR 上下文中,这看起来没问题。但是,如果我们将它放在一个带有 dir="rtl" 或 writing-mode: vertical-rl 的容器中,布局就会被破坏。装饰性边框在错误的一侧,头像在错误的一侧,外边距不正确,圆角也错位了。
“新”方法:稳健的、基于逻辑属性的卡片
现在,让我们使用逻辑属性重构相同的组件。我们将利用 Level 1 和 Level 2 新增的属性。
/* --- CSS (逻辑属性) --- */
.logical-card {
inline-size: 300px;
padding: 20px; /* `padding` 简写本身就是逻辑的! */
margin-block-end: 20px;
border: 1px solid #ccc;
border-inline-start: 5px solid darkcyan;
border-start-start-radius: 8px; /* Level 2 的强大功能! */
border-end-start-radius: 8px; /* Level 2 的强大功能! */
}
.logical-card .avatar {
float: inline-start; /* Level 2 的强大功能! */
inline-size: 80px;
block-size: 80px;
margin-inline-end: 15px;
}
.logical-card h3 {
margin-block-start: 0;
text-align: start;
}
测试与验证
有了这个新的 CSS,你可以将组件放入任何容器中,它都会自动适应。
- 在 LTR 上下文中:它将看起来与原始的物理版本完全相同。
- 在 RTL 上下文中 (dir="rtl"):头像将浮动到右侧,其外边距将在左侧,装饰性边框将在右侧,文本将起始对齐(即右对齐)。圆角将正确地位于右上角和右下角。它就是这么好用。
- 在垂直上下文中 (writing-mode: vertical-rl):卡片的“宽度”(现在是其垂直的 inline-size)将是 300px。头像将浮动到“顶部”(inline-start),其外边距在其“底部”(inline-end)。装饰性边框将在右侧(inline-start),圆角将位于右上角和左上角。该组件完全正确地重新定位了自己,无需任何媒体查询或覆盖。
浏览器支持与回退方案
这一切听起来都很棒,但浏览器支持情况如何呢?好消息是,所有现代浏览器对 Level 1 逻辑属性的支持都非常好。您现在就可以并且应该使用像 margin-inline-start 和 padding-block 这样的属性。
对较新的 Level 2 功能的支持正在迅速改善,但尚未普及。float、clear 和 resize 的逻辑值得到了很好的支持。逻辑 border-radius 属性是最新推出的,可能仍处于功能标志之后或仅在最新的浏览器版本中提供。与往常一样,您应该查阅像 MDN Web Docs 或 CanIUse.com 这样的资源以获取最新的兼容性数据。
渐进增强策略
由于 CSS 的设计具有弹性,我们可以轻松地为旧版浏览器提供回退方案。层叠机制将确保如果浏览器不理解某个逻辑属性,它会简单地忽略它,并使用在其之前定义的物理属性。
以下是编写具有回退功能的 CSS 的方法:
.card {
/* 为旧版浏览器提供的回退方案 */
border-left: 5px solid darkcyan;
border-top-left-radius: 8px;
/* 将覆盖回退方案的现代逻辑属性 */
border-inline-start: 5px solid darkcyan;
border-start-start-radius: 8px;
}
这种方法确保了为每个人提供坚实的基础体验,同时为使用现代浏览器的用户提供了增强的、自适应的布局。对于不需要支持多种书写模式的项目来说,这可能有些多余。但对于任何全球性应用程序、设计系统或主题来说,这是一种稳健且面向未来的策略。
未来是逻辑的:超越 Level 2
从物理思维到逻辑思维的转变是现代 CSS 中最重要的转变之一。它使我们的样式语言与多样化、全球化的 Web 现实保持一致。它让我们从脆弱的、面向屏幕的 hack 转向弹性的、面向内容的设计。
还有空白吗?有一些。像 background-position 或渐变的逻辑值仍在讨论中。但随着 Level 2 的发布,绝大多数日常布局和样式任务现在都可以使用纯粹的逻辑方法来完成。
对开发人员的行动号召很明确:开始默认使用逻辑属性。让 inline-size 成为你的首选,而不是 width。使用 margin-inline 而不是分别设置左右外边距。这不仅仅是为了支持不同的语言;这是为了编写更好、更具弹性的 CSS。用逻辑属性构建的组件本质上更具可重用性和适应性,无论它是在 LTR、RTL 还是垂直布局中使用。这简直是更好的工程实践。
结论:拥抱“流”
CSS 逻辑属性 Level 2 不仅仅是新功能的集合;它是一个愿景的完成。它提供了构建尊重其内容自然流动的布局所需的最后关键部分,无论这种流动是什么。通过拥抱像 float: inline-start 和 border-start-start-radius 这样的属性,我们将我们的技艺从简单地在屏幕上定位盒子,提升到设计真正全球化、包容且面向未来的 Web 体验。
下次你开始一个新项目或构建一个新组件时,在你输入 margin-left 之前停顿一下。问问自己,“我指的是左边,还是开始的位置?”通过做出这个小小的思维转变,你将为每个人、在任何地方,构建一个更具适应性和可访问性的 Web 做出贡献。